---
title: 'Debugging in Cypress'
description: 'Learn how to use debugger, .debug(), .pause(), and the Developer Tools to debug Cypress tests.'
sidebar_label: 'Debugging'
---

<ProductHeading product="app" />

# Debugging

:::info

##### <Icon name="question-circle" color="#4BBFD2" /> What you'll learn

- How to use `debugger` and `.debug()` within Cypress tests
- How to step through test commands with `.pause()`
- How to use the Developer Tools to get console logs for command information
- How errors are displayed and structured within Cypress
- How to debug flaky tests

:::

## Using debugger

Your Cypress test code runs in the same run loop as your application. This means
you have access to the code running on the page, as well as the things the
browser makes available to you, like `document`, `window`, and `debugger`.

### Debug just like you always do

Based on those statements, you might be tempted to throw a `debugger` into your
test, like so:

:::visit-mount-example

```js
it('let me debug like a fiend', () => {
  -{cy.visit('/my/page/path')::cy.mount(<MyComponent />)}-

  cy.get('[data-testid="selector-in-question"]')

  debugger // Doesn't work
})
```

:::

This may not work exactly as you are expecting. As you may remember from the
[Introduction to Cypress](/app/core-concepts/introduction-to-cypress), `cy`
commands enqueue an action to be taken later. Can you see what the test above
will do given that perspective?

Both [`cy.visit()`](/api/commands/visit) and [`cy.get()`](/api/commands/get)
will return immediately, having enqueued their work to be done later, and
`debugger` will be executed before any of the commands have actually run. The
same behavior is expected in Component Tests when using
[`cy.mount()`](/api/commands/mount).

Let's use [`.then()`](/api/commands/then) to tap into the Cypress command during
execution and add a `debugger` at the appropriate time:

:::visit-mount-example

```js
it('let me debug when the after the command executes', () => {
  -{cy.visit('/my/page/path')::cy.mount(<MyComponent />)}-

  cy.get('[data-testid="selector-in-question"]').then(($selectedElement) => {
    // Debugger is hit after the cy.visit
    // and cy.get commands have completed
    debugger
  })
})
```

:::

Now we're in business! When you're visiting a page or mounting a component for
the first time, (shown above with the [`cy.get()`](/api/commands/get)chain and
its [`.then()`](/api/commands/then) attached) the commands are enqueued for
Cypress to execute. The `it` block exits, and Cypress starts its work:

1. In an end-to-end test, the page is visited and Cypress waits for it to load.
   Alternatively, the component is mounted and rendered in a Component Test.
2. The element is queried, and Cypress automatically waits and retries for a few
   moments if it isn't found immediately.
3. The function passed to [`.then()`](/api/commands/then) is executed, with the
   found element yielded to it.
4. Within the context of the [`.then()`](/api/commands/then) function, the
   `debugger` is called, halting the browser and calling focus to the Developer
   Tools.
5. You're in! Inspect the state of your application like you normally would if
   you'd dropped the `debugger` into your application code.

### Using [`.debug()`](/api/commands/debug)

Cypress also exposes a shortcut for debugging commands,
[`.debug()`](/api/commands/debug). Let's rewrite the test above using this
helper method:

:::visit-mount-example

```js
it('let me debug like a fiend', () => {
  -{cy.visit('/my/page/path')::cy.mount(<MyComponent />)}-

  cy.get('[data-testid="selector-in-question"]').debug()
})
```

:::

The current subject that is yielded by the [`cy.get()`](/api/commands/get) is
exposed as the variable `subject` within your Developer Tools so that you can
interact with it in the console.

<DocsImage
  src="/img/app/debugging/debugging-subject.png"
  alt="Debugging Subject"
/>

Use [`.debug()`](/api/commands/debug) to quickly inspect any (or many!) part(s)
of your application during the test. You can attach it to any Cypress chain of
commands to have a look at the system's state at that moment.

## Step through test commands

You can run the test command by command using the
[`.pause()`](/api/commands/pause) command.

```javascript
it('adds items', () => {
  cy.pause()
  cy.get('[data-testid="new-todo"]')
  // more commands
})
```

This allows you to inspect the web application, the DOM, the network, and any
storage after each command to make sure everything happens as expected.

## Using the Developer Tools

Though Cypress has built out
[an excellent application](/app/core-concepts/open-mode) to help you
understand what is happening in your application and your tests, there's no
replacing all the amazing work browser teams have done on their built-in
development tools. Once again, we see that Cypress goes _with_ the flow of the
modern ecosystem, opting to leverage these tools wherever possible.

:::info

### <Icon name="video" /> See it in action!

You can see a walk-through of debugging some application code from Cypress
[in this segment from our React tutorial series](https://vimeo.com/242961930#t=264s).

:::

### Get console logs for commands

All of Cypress's commands, when clicked on within the
[Command Log](/app/core-concepts/open-mode#Command-Log), print extra
information about the command, its subject, and its yielded result. Try clicking
around the Command Log with your Developer Tools open! You may find some useful
information here.

#### When clicking on `.type()` command, the Developer Tools console outputs the following:

<DocsImage
  src="/img/api/type/console-log-of-typing-with-entire-key-events-table-for-each-character.png"
  alt="Console Log type"
/>

## Errors

Sometimes tests fail. Sometimes we want them to fail, just so we know they're
testing the right thing when they pass. But other times, tests fail
unintentionally and we need to figure out why. Cypress provides some tools to
help make that process as easy as possible.

### Anatomy of an error

Let's take a look at the anatomy of an error and how it is displayed in Cypress,
by way of a failing test.

```js
it('reroutes on users page', () => {
  cy.contains('Users').click()
  cy.url().should('include', 'users')
})
```

The center of the `<li>Users</li>` element is hidden from view in our
application under test, so the test above will fail.

<AnatomyOfAnError />

### Source maps

<SourceMaps />

## Debugging flake

While Cypress is
[flake-resistant](/app/get-started/why-cypress#Flake-resistant), some users
do experience flake, particularly when running in CI versus locally.

:::tip
To debug flake in your recorded tests in CI, try out [Test Replay](/cloud/features/test-replay) in Cypress Cloud.
It allows you to replay the test exactly as it ran in CI.
:::

Most often
in cases of flaky tests, we see that there are not enough assertions surrounding
test actions or network requests before moving on to the next assertion.

If there is any variation in the speed of the network requests or responses when
run locally versus in CI, then there can be failures in one over the other.

Because of this, we recommend asserting on as many required steps as possible
before moving forward with the test. This also helps later to isolate where the
exact failure is when debugging.

Flake can also occur when there are differences between your local and CI
environments. You can use the following methods troubleshoot tests that pass
locally but fail in CI.

- Review your CI build process to ensure nothing is changing with your
  application that would result in failing tests.
- Remove time-sensitive variability in your tests. For example, ensure a network
  request has finished before looking for the DOM element that relies on the
  data from that network request. You can leverage
  [aliasing](/app/core-concepts/variables-and-aliases#Aliases) for this.

Cypress Cloud also offers [Analytics](/cloud/features/analytics/overview) that illustrate
trends in your tests and can help identify the tests that flake or fail most often. This
could help narrow down what is causing the flake -- for example, seeing
increased failures after a change to the test environment could indicate issues
with the new environment.

For more advice on dealing with flake read a
[series of our blog posts](https://cypress.io/blog/tag/flake/) and
[Identifying Code Smells in Cypress](https://codingitwrong.com/2020/10/09/identifying-code-smells-in-cypress.html).

## Log Cypress events

Cypress emits multiple events you can listen to as shown below.
[Read more about logging events in the browser here](/api/cypress-api/catalog-of-events#Logging-All-Events).

<DocsImage
  src="/img/api/catalog-of-events/console-log-events-debug.png"
  alt="console log events for debugging"
/>

## Troubleshooting Cypress

There are times when you'll encounter errors or unexpected behavior with
Cypress itself. In this situation, we recommend checking out our
[Troubleshooting Guide](/app/references/troubleshooting).

## More info

Often debugging a failing Cypress test means understanding better how your own
application works, and how the application might race against the test commands.
We recommend reading these blog posts where we show common error scenarios and
how to solve them:

- [When Can The Test Start?](https://www.cypress.io/blog/2018/02/05/when-can-the-test-start/)
- [When Can The Test Stop?](https://www.cypress.io/blog/2020/01/16/when-can-the-test-stop/)
- [When Can The Test Click?](https://www.cypress.io/blog/2019/01/22/when-can-the-test-click/)
- [When Can The Test Log Out?](https://www.cypress.io/blog/2020/06/25/when-can-the-test-log-out/)
- [Do Not Get Too Detached](https://www.cypress.io/blog/2020/07/22/do-not-get-too-detached/)
